package plenprojects.chatroomcontrollers;

import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import plenprojects.chatservice.ChatRoom;
import plenprojects.chatservice.ChatService;
import plenprojects.model.ChatMessage;
import plenprojects.model.ServerError;
import plenprojects.model.ServerMessage;
import plenprojects.security.Permission;
import plenprojects.security.PermissionType;
import plenprojects.security.SecurityToken;

@Controller
@RequestMapping("/chat")
public class ChatRoomController {//TODO CHANGE first check token
	
	@Autowired
	private ChatService service;
	
	@RequestMapping(value = "/{token}/{roomname}/recent", method = RequestMethod.GET)
	public @ResponseBody ServerMessage getRecent(@PathVariable String roomname, @PathVariable String token) {
		
		ServerMessage response = new ServerMessage();
		
		ChatRoom room = service.getRoom(roomname);
		
		if(room == null) {
			
			return new ServerError("Chat room " + roomname + " doesn't exist.");
		}
		
		if(!service.isAuthorized(token, roomname, PermissionType.CAN_READ)) {
			
			return new ServerError("Token " + token + " is not authorized to read from a room " + roomname + ".");
		}
		
		Queue<ChatMessage> recent = room.getRecentMessages();
		
		List<Map<String, String>> convertedMessages = new LinkedList<Map<String, String>>();
		
		for(ChatMessage msg : recent) {
			
			convertedMessages.add(msg.convertToMap());
		}
		
		response.setParameter("success", true);
		response.setParameter("messages", convertedMessages);
		
		return response;
	}
	
	@RequestMapping(value = "/{token}/{roomname}/{after}/recent", method = RequestMethod.GET)
	public @ResponseBody ServerMessage getRecentAfter(@PathVariable String roomname, @PathVariable String token, @PathVariable String after) {
		
		ServerMessage response = new ServerMessage();
		
		ChatRoom room = service.getRoom(roomname);
		
		if(room == null) {
			
			return new ServerError("Chat room " + roomname + " doesn't exist.");
		}
		
		if(!service.isAuthorized(token, roomname, PermissionType.CAN_READ)) {
			
			return new ServerError("Token " + token + " is not authorized to read from a room " + roomname + ".");
		}
		
		Queue<ChatMessage> recent = room.getRecentMessages();
		Iterator<ChatMessage> iter = recent.iterator();
		
		while(iter.hasNext()) {
			
			ChatMessage msg = iter.next();
			
			String strTime = msg.getTime();
			
			if(strTime.compareTo(after) < 0) {
				
				iter.remove();
			}
		}
		
		List<Map<String, String>> convertedMessages = new LinkedList<Map<String, String>>();
		
		for(ChatMessage msg : recent) {
			
			convertedMessages.add(msg.convertToMap());
		}
		
		response.setParameter("success", true);
		response.setParameter("messages", convertedMessages);
		return response;
	}
	
	@RequestMapping(value = "/{token}/{roomname}/post", method = RequestMethod.POST)
	public @ResponseBody ServerMessage postMessage(@PathVariable String roomname, @PathVariable String token, @RequestBody ServerMessage request) {
		
		ChatRoom room = service.getRoom(roomname);
		
		if(room == null) {
			
			return new ServerError("Chat room " + roomname + " doesn't exist.");
		}
		
		SecurityToken sToken = service.toToken(token);
		
		if(sToken == null) {
			
			return new ServerError("Token " + token + " is invalid");
		}
		
		if(!service.isAuthorized(token, roomname, PermissionType.CAN_WRITE)) {
			
			return new ServerError("Token " + token + " is not authorized to write in a room " + roomname + ".");
		}
		
		String message = (String)request.getParameter("message");
		
		if(message == null) {
			
			return new ServerError("Message not set.");
		}
		
		SecurityToken tok = service.toToken(token);
		
		room.submitNewMessage(new ChatMessage(message, tok.getUsername(), ChatMessage.dateToString(new Date())));
		
		ServerMessage response = new ServerMessage();
		response.setParameter("success", true);
		return response;
	}
	
	@RequestMapping(value = "/{token}/{roomname}/create", method = RequestMethod.POST)
	public @ResponseBody ServerMessage createChatRoom(@PathVariable String token, @PathVariable String roomname) {//TODO prob bad
		
		SecurityToken sToken = service.toToken(token);
		
		if(sToken == null) {
			
			return new ServerError("Token " + token + " is invalid");
		}
		
		if(service.roomExists(roomname)) {
			
			return new ServerError("Room " + roomname + " already exists.");
		}
		
		ChatRoom newRoom = new ChatRoom(roomname, new PermissionType[] { PermissionType.CAN_READ, PermissionType.CAN_WRITE });
		
		sToken.addPermission(new Permission(roomname, PermissionType.CAN_JOIN));
		sToken.addPermission(new Permission(roomname, PermissionType.CAN_INVITE));
		sToken.addPermission(new Permission(roomname, PermissionType.CAN_READ));
		sToken.addPermission(new Permission(roomname, PermissionType.CAN_WRITE));
		sToken.addPermission(new Permission(roomname, PermissionType.CAN_KICK));
		
		service.addRoom(newRoom);
		
		ServerMessage response = new ServerMessage();
		response.setParameter("success", true);
		return response;
	}
	
	@RequestMapping(value = "/{token}/{roomname}/join", method = RequestMethod.POST)
	public @ResponseBody ServerMessage joinRoom(@PathVariable String token, @PathVariable String roomname) {
		
		ChatRoom room = service.getRoom(roomname);
		
		if(room == null) {
			
			return new ServerError("Room " + roomname + " doesn't exist.");
		}
		
		SecurityToken sToken = service.toToken(token);
		
		if(sToken == null) {
			
			return new ServerError("Token " + token + " is invalid");
		}
		
		if(!service.isAuthorized(token, roomname, PermissionType.CAN_JOIN)) {
			
			return new ServerError("Token " + token + " is not authorized to join " + roomname + ".");
		}
		
		if(room.isIn(sToken.getUsername())) {
			
			return new ServerError(sToken.getUsername() + " is already in a chat room " + roomname);
		}
		
		for(PermissionType pt : room.getPermissionsOnJoin()) {
			
			sToken.addPermission(new Permission(roomname, pt));
		}
		
		room.addUser(sToken.getUsername());
		
		ServerMessage response = new ServerMessage();
		response.setParameter("success", true);
		return response;
	}
	
	@RequestMapping(value = "/{token}/{roomname}/leave", method = RequestMethod.POST)
	public @ResponseBody ServerMessage leaveRoom(@PathVariable String token, @PathVariable String roomname) {
		
		ChatRoom room = service.getRoom(roomname);
		
		if(room == null) {
			
			return new ServerError("Room " + roomname + " doesn't exist.");
		}
		
		SecurityToken sToken = service.toToken(token);
		
		if(sToken == null) {
			
			return new ServerError("Token " + token + " is invalid");
		}
		
		if(!room.isIn(sToken.getUsername())) {
			
			return new ServerError("Token " + token + " is not in " + roomname + " chat room.");
		}
		
		sToken.removePermission(roomname, PermissionType.CAN_READ);
		sToken.removePermission(roomname, PermissionType.CAN_WRITE);
		room.removeUser(sToken.getUsername());
		
		ServerMessage response = new ServerMessage();
		response.setParameter("success", true);
		return response;
	}
	
	@RequestMapping(value = "/{token}/{roomname}/{who}/invite", method = RequestMethod.POST)
	public @ResponseBody ServerMessage inviteUser(@PathVariable String token, @PathVariable String roomname, @PathVariable String who) {
		
		SecurityToken sToken = service.toToken(token);
		
		if(sToken == null) {
			
			return new ServerError("Token " + token + " is invalid.");
		}
		
		if(!service.isAuthorized(token, roomname, PermissionType.CAN_INVITE)) {
			
			return new ServerError("Token " + token + " is not authorized to invite users to the room " + roomname + ".");
		}
		
		ChatRoom room = service.getRoom(roomname);
		
		if(room == null) {
			
			return new ServerError("Room " + roomname + " doesn't exist.");
		}
		
		SecurityToken inviteMe = service.usernameToToken(who);
		
		if(inviteMe == null) {
			
			return new ServerError("User " + who + " cannot be invited.");
		}
		
		inviteMe.addPermission(new Permission(roomname, PermissionType.CAN_JOIN));
		
		ServerMessage response = new ServerMessage();
		response.setParameter("success", true);
		return response;
	}
	
	@RequestMapping(value = "/{token}/{roomname}/{who}/kick", method = RequestMethod.POST)//TODO 100% its bad
	public @ResponseBody ServerMessage kickUser(@PathVariable String token, @PathVariable String roomname, @PathVariable String who) {
		
		SecurityToken sToken = service.toToken(token);
		
		if(sToken == null) {
			
			return new ServerError("Token " + token + " is invalid.");
		}
		
		if(!service.isAuthorized(token, roomname, PermissionType.CAN_KICK)) {
			
			return new ServerError("Token " + token + " is not authorized to kick users from the room " + roomname + ".");
		}
		
		ChatRoom room = service.getRoom(roomname);
		
		if(room == null) {
			
			return new ServerError("Room " + roomname + " doesn't exist.");
		}
		
		SecurityToken kickMe = service.usernameToToken(who);
		
		if(kickMe == null) {
			
			return new ServerError("User " + who + " cannot be kicked.");
		}
		
		kickMe.removePermission(roomname, PermissionType.CAN_READ);
		kickMe.removePermission(roomname, PermissionType.CAN_WRITE);
		room.removeUser(who);
		
		ServerMessage response = new ServerMessage();
		response.setParameter("success", true);
		return response;
	}
}
